package post

import (
	"context"
	// "fmt"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/forum/model"
	"mall/service/forum/rpc/internal/svc"
	"mall/service/forum/rpc/internal/utils"
	"mall/service/forum/rpc/types/forum"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetReviewByIdLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetReviewByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetReviewByIdLogic {
	return &GetReviewByIdLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *GetReviewByIdLogic) GetReviewById(in *forum.BaseIdReq) (*forum.ForumPostInfo, error) {
	if (in.Filter == nil || len(*in.Filter) == 0) && (in.Id == nil || *in.Id == 0) {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.ParsePreloadAndEagerLoad(in.Preload, in.EagerLoad)

	// logrus.Info(fmt.Sprintf("GetReviewById preloadMap: %+v", preloadMap))
	// map[Card:[ObjectId ObjectType LinkUrl PicUrl Title Subtitle Label Price] Media:[] Meta:[] Term:[] forumPost:[Id Title AuthorId AuthorName AuthorAvatar AuthorRankId AuthorRoleId ContentHtml Excerpt CommentStatus PublicDate PhotoCount] productMedia:[Id Url Thumbnail Order altText metaData] productMeta:[mediaId mediaUrl viewCount commentCount forwardCount] productTerm:[Id Name Slug]]
	// logrus.Info(fmt.Sprintf("GetReviewById eagerLoadMap: %+v", eagerLoadMap))
	// map[forumPost:[Media Meta Card Term]]

	forumPostEntityName := model.RpcEntityNames.ForumPost
	if _, ok := model.RpcEntityPreloadMap[forumPostEntityName]; !ok {
		return &forum.ForumPostInfo{}, nil
	}

	forumPostRepositoryName := model.RepositoryNames.ForumPost
	columnMap, ok := model.RepositoryPreloadMap[forumPostRepositoryName]
	if !ok {
		return &forum.ForumPostInfo{}, nil
	}

	var post *model.ForumPost
	if in.Filter != nil && len(*in.Filter) > 0 {
		var selectCols []string
		if preloadFields, ok := preloadMap[forumPostEntityName]; ok {
			selectCols = modelx.ParseSelectColumns(preloadFields, columnMap)
		}
		selectCols = append(selectCols, model.ForumPostColumns.PostAuthorID)
		selectCols = append(selectCols, model.ForumPostColumns.PostStatus)

		filterMap := modelx.ParseFilter(in.Filter, columnMap)
		// logrus.Info(fmt.Sprintf("GetReviewById filterMap: %+v", filterMap))
		// map[forum_id:map[equalTo:[11]] post_author_id:map[equalTo:[10021]] post_status:map[notEqualTo:[3]]]

		if filterMap == nil {
			return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
		}

		if in.Id != nil && *in.Id > 0 {
			filterMap[model.ForumPostColumns.PostID] = map[string][]any{
				"equalTo": {*in.Id},
			}
		}

		orderBy := modelx.ParseSorter(in.Sorter, columnMap)
		// logrus.Info(fmt.Sprintf("GetReviewById orderBy: %s", orderBy))
		//
		if len(orderBy) == 0 {
			orderBy = model.ForumPostColumns.PostID + " DESC"
		}

		res, _, err := l.svcCtx.Post.GetList(l.ctx, model.M{
			"pageSize": uint64(1),
			"orderBy":  orderBy,
			"select":   strings.Join(selectCols, ","),
		}, -1, filterMap)
		if err != nil {
			return nil, err
		}

		if len(res) == 0 {
			return &forum.ForumPostInfo{}, nil
		}

		post = res[0]
	} else {
		data, err := l.svcCtx.Post.FindOne(l.ctx, *in.Id)
		if err != nil {
			return nil, err
		}

		post = data
	}

	if post == nil {
		return &forum.ForumPostInfo{}, nil
	}

	if post.PostStatus == uint8(globalkey.StatusDeleted) {
		return &forum.ForumPostInfo{}, nil
	}

	if in.VisitorId != nil && *in.VisitorId != post.PostAuthorID && post.PostStatus != uint8(globalkey.StatusApproved) {
		return &forum.ForumPostInfo{}, nil
	}

	var authorSignature *string
	if post.PostAuthorID > 0 {
		author, err := l.svcCtx.User.FindOne(l.ctx, post.PostAuthorID)
		if err != nil {
			logx.Infow("GetReviewById User.FindOne error", logx.Field("detail", err.Error()))
		} else if author != nil && len(author.Signature) > 0 {
			authorSignature = &author.Signature
		}
	}

	pid := post.PostID
	subEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
	if eagerLoadEntities, ok := eagerLoadMap[forumPostEntityName]; ok {
		for _, entity := range eagerLoadEntities {
			if entitySettingMap, ok := model.RpcEntityPreloadMap[entity]; ok {
				subEntitySettingMap[entity] = entitySettingMap
			}
		}
	}

	var media []*forum.MediaInfo
	forumMediaEntityName := model.RpcEntityNames.ForumMedia
	if _, ok := subEntitySettingMap[forumMediaEntityName]; ok {
		forumMediaRepositoryName := model.RepositoryNames.ForumMedia
		subPreloadFields, hasSubPreloadFields := preloadMap[forumMediaEntityName]
		subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[forumMediaRepositoryName]
		if hasSubPreloadFields && hasSubColumnMap {
			subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.ForumAttachmentRelationshipColumns.ObjectID] = map[string][]any{
				"equalTo": {pid},
			}
			subFilterMap[model.ForumAttachmentRelationshipColumns.ObjectType] = map[string][]any{
				"equalTo": {globalkey.AttachmentLogTypeForumPost},
			}
			orderBy := model.ForumAttachmentRelationshipColumns.AttachmentThumbnail + " DESC," +
				model.ForumAttachmentRelationshipColumns.AttachmentOrder
			list, _, err := l.svcCtx.Post.GetMedia(l.ctx, model.M{
				"orderBy": orderBy,
				"select":  strings.Join(subSelectCols, ","),
			}, -1, subFilterMap)
			if err != nil {
				return nil, err
			}

			if len(list) > 0 {
				for _, v := range list {
					media = append(media, &forum.MediaInfo{
						Uid:       &v.AttachmentRelationshipID,
						Id:        pointy.GetPointer(strconv.FormatUint(v.AttachmentID, 10)),
						Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
						Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
						Uri:       &v.AttachmentSource,
						Url:       &v.AttachmentImageURL,
						AltText:   &v.AttachmentImageAlt,
						MetaData:  &v.AttachmentImageMeta,
					})
				}
			}
		}
	}

	var meta []*forum.MetaInfo
	forumPostMetaEntityName := model.RpcEntityNames.ForumPostMeta
	if entitySettingMap, ok := subEntitySettingMap[forumPostMetaEntityName]; ok {
		if subPreloadFields, ok := preloadMap[forumPostMetaEntityName]; ok {
			var metaKeys []any
			metaKeyMap := make(map[string]string)
			for _, field := range subPreloadFields {
				if fieldSetting, ok := entitySettingMap[field]; ok && len(fieldSetting.Name) > 0 {
					metaKeys = append(metaKeys, fieldSetting.Name)
					metaKeyMap[fieldSetting.Name] = field
				}
			}
			if len(metaKeys) > 0 {
				subFilterMap := make(map[string]map[string][]any)
				subFilterMap[model.ForumPostMetumColumns.PostID] = map[string][]any{
					"equalTo": {pid},
				}
				subFilterMap[model.ForumPostMetumColumns.MetaKey] = map[string][]any{
					"in": metaKeys,
				}
				orderBy := model.ForumPostMetumColumns.MetaID + " DESC"
				list, _, err := l.svcCtx.Post.GetMeta(l.ctx, model.M{
					"orderBy": orderBy,
				}, -1, subFilterMap)
				if err != nil {
					return nil, err
				}

				if len(list) > 0 {
					metaKeys = make([]any, 0) // 二次查询的metaKey
					metaMap := make(map[string]string)
					for _, v := range list {
						key := v.MetaKey
						if len(key) > 0 && v.MetaValue.Valid {
							val := v.MetaValue.String
							if key == "_note" || key == "_grade" {
								metaKeys = append(metaKeys, val)
								metaMap[val] = key
							} else if field, ok := metaKeyMap[key]; ok {
								meta = append(meta, &forum.MetaInfo{
									Id:    pointy.GetPointer(v.MetaID),
									Key:   pointy.GetPointer(field),
									Value: pointy.GetPointer(val),
								})
							}
						}
					}

					if len(metaKeys) > 0 { // 二次查询
						metaFilterMap := make(map[string]map[string][]any)
						metaFilterMap[model.ForumPostMetumColumns.PostID] = map[string][]any{
							"equalTo": {pid},
						}
						metaFilterMap[model.ForumPostMetumColumns.MetaKey] = map[string][]any{
							"in": metaKeys,
						}
						metaList, _, err := l.svcCtx.Post.GetMeta(l.ctx, model.M{
							"orderBy": orderBy,
						}, -1, metaFilterMap)
						if err != nil {
							return nil, err
						}

						if len(metaList) > 0 {
							for _, v := range metaList {
								key := v.MetaKey
								if len(key) > 0 && v.MetaValue.Valid {
									val := v.MetaValue.String
									if prefix, ok := metaMap[key]; ok {
										if prefix == "_note" {
											meta = append(meta, &forum.MetaInfo{
												Id:    pointy.GetPointer(v.MetaID),
												Key:   pointy.GetPointer("Note:" + key),
												Value: pointy.GetPointer(val),
											})
										} else if prefix == "_grade" {
											meta = append(meta, &forum.MetaInfo{
												Id:    pointy.GetPointer(v.MetaID),
												Key:   pointy.GetPointer("Grade:" + key),
												Value: pointy.GetPointer(val),
											})
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	var cards []*forum.PostCardInfo
	forumCardEntityName := model.RpcEntityNames.ForumCard
	if _, ok := subEntitySettingMap[forumCardEntityName]; ok {
		forumCardRepositoryName := model.RepositoryNames.ForumCard
		subPreloadFields, hasSubPreloadFields := preloadMap[forumCardEntityName]
		subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[forumCardRepositoryName]
		if hasSubPreloadFields && hasSubColumnMap {
			subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.ForumPostCardColumns.PostID] = map[string][]any{
				"equalTo": {pid},
			}
			list, _, err := l.svcCtx.Post.GetCard(l.ctx, model.M{
				"select": strings.Join(subSelectCols, ","),
			}, -1, subFilterMap)
			if err != nil {
				return nil, err
			}

			if len(list) > 0 {
				for _, v := range list {
					cardType := utils.FormatCardType(int32(v.ObjectType))
					cards = append(cards, &forum.PostCardInfo{
						Uid:      &v.ID,
						Id:       &v.ObjectID,
						Type:     pointy.GetPointer(cardType),
						LinkUrl:  &v.LinkURL,
						Title:    &v.Title,
						PicUrl:   &v.PicURL,
						Subtitle: &v.Subtitle,
						Label:    &v.Label,
						Price:    &v.Price,
					})
				}
			}
		}
	}

	var tags []*forum.TermInfo
	forumTermEntityName := model.RpcEntityNames.ForumTerm
	if _, ok := subEntitySettingMap[forumTermEntityName]; ok {
		forumTermRepositoryName := model.RepositoryNames.ForumTerm
		subPreloadFields, hasSubPreloadFields := preloadMap[forumTermEntityName]
		subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[forumTermRepositoryName]
		if hasSubPreloadFields && hasSubColumnMap {
			subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.ForumTermRelationshipColumns.ObjectID] = map[string][]any{
				"equalTo": {pid},
			}
			subFilterMap[model.ForumTermRelationshipColumns.ObjectType] = map[string][]any{
				"equalTo": {globalkey.AttachmentLogTypeForumPost},
			}
			list, _, err := l.svcCtx.ForumTerm.GetRelationshipList(l.ctx, model.M{
				"select": model.ForumTermRelationshipColumns.TermID,
			}, -1, subFilterMap)
			if err != nil {
				return nil, err
			}

			if len(list) > 0 {
				var tids []any
				for _, v := range list {
					tids = append(tids, v.TermID)
				}

				termFilterMap := make(map[string]map[string][]any)
				termFilterMap[model.ForumTermColumns.TermID] = map[string][]any{
					"in": tids,
				}
				subSelectCols = append(subSelectCols, model.ForumTermColumns.Taxonomy) // 必须获取以区分category及tag
				termList, _, err := l.svcCtx.ForumTerm.GetList(l.ctx, model.M{
					"select": strings.Join(subSelectCols, ","),
				}, -1, termFilterMap)
				if err != nil {
					return nil, err
				}

				for _, v := range termList {
					if v.Taxonomy == uint16(globalkey.TermTaxonomyReviewTag) {
						tags = append(tags, &forum.TermInfo{
							Id:   pointy.GetPointer(v.TermID),
							Name: pointy.GetPointer(v.Name),
							Slug: pointy.GetPointer(v.Slug),
						})
					}
				}
			}
		}
	}

	if in.SearchLogId != nil {
		var visitorId uint64
		if in.VisitorId != nil {
			visitorId = *in.VisitorId
		}
		var platformId uint
		if in.PlatformId != nil {
			platformId = uint(*in.PlatformId)
		}
		l.svcCtx.User.InsertClickLog(l.ctx, nil, &model.ForumUserClickLog{
			UserID:      visitorId,
			PlatformID:  platformId,
			SearchLogID: *in.SearchLogId,
			ObjectID:    pid,
			ObjectType:  uint16(globalkey.AttachmentLogTypeForumPost),
			CreatedAt:   time.Now(),
		})
	}

	return &forum.ForumPostInfo{
		Id:              pointy.GetPointer(pid),
		PostTitle:       &post.PostTitle,
		PostContent:     &post.PostContent,
		PostExcerpt:     &post.PostExcerpt,
		ForumId:         &post.ForumID,
		TopicId:         &post.TopicID,
		ParentId:        &post.ParentID,
		AuthorId:        &post.PostAuthorID,
		Status:          pointy.GetPointer(uint32(post.PostStatus)),
		CommentStatus:   pointy.GetPointer(uint32(post.CommentStatus)),
		Sort:            pointy.GetPointer(uint32(post.Sort)),
		CreatedAt:       pointy.GetPointer(modelx.FormatTime(post.PostDate, "")),
		UpdatedAt:       pointy.GetPointer(modelx.FormatTime(post.PostModifiedDate, "")),
		AuthorAvatar:    &post.PostAuthorAvatar,
		AuthorNickname:  &post.PostAuthorNickname,
		AuthorSignature: authorSignature,
		AuthorRankId:    pointy.GetPointer(uint32(post.PostAuthorRankID)),
		AuthorRoleId:    pointy.GetPointer(uint32(post.PostAuthorRoleID)),
		// Sticky:        pointy.GetPointer(uint32(post.Sticky)),
		// CommentCount:  pointy.GetPointer(uint32(post.CommentCount)),
		// PhotoCount:     pointy.GetPointer(uint32(post.PhotoCount)),
		Media: media,
		Meta:  meta,
		Cards: cards,
		Tags:  tags,
	}, nil
}
